Manually update toplevel_under_pointer when a grab changes to owner_events
authorAlexander Larsson <alexl@redhat.com>
Fri, 10 Jul 2009 15:30:42 +0000 (17:30 +0200)
committerAlexander Larsson <alexl@redhat.com>
Fri, 10 Jul 2009 15:38:05 +0000 (17:38 +0200)
When we ungrab the pointer we don't get enter events for the window the
pointer is in at the time of the ungrab, so we manually query for the
window the pointer is in. The same thing actually happens on re-grab if
the previous grab was !owner_events (meaning we don't get crossing events
for windows other than the grab) but the new grab is owner_events (and
thus non-grab windows need to get crossing events).

This factors out some common code and enables it also for the re-grab
to owner_events case.

gdk/gdkdisplay.c

index 399d1939992f8b698ee55bbc44e31c49ed224fcc..ff11f086fc72948c63460fa79c843f01f5b31257 100644 (file)
@@ -903,6 +903,42 @@ synthesize_crossing_events (GdkDisplay *display,
     }
 }
 
+static GdkWindow *
+get_current_toplevel (GdkDisplay *display,
+                     int *x_out, int *y_out,
+                     GdkModifierType *state_out)
+{
+  GdkWindow *pointer_window;
+  GdkWindowObject *w;
+  int x, y;
+  GdkModifierType state;
+
+  pointer_window = _gdk_windowing_window_at_pointer (display,  &x, &y, &state);
+  if (pointer_window != NULL &&
+      (GDK_WINDOW_DESTROYED (pointer_window) ||
+       GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
+       GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
+    pointer_window = NULL;
+
+  w = (GdkWindowObject *)pointer_window;
+  if (w)
+    {
+      /* Convert to toplevel */
+      while (w->parent != NULL &&
+            w->parent->window_type != GDK_WINDOW_ROOT)
+       {
+         x += w->x;
+         y += w->y;
+         w = w->parent;
+       }
+    }
+
+  *x_out = x;
+  *y_out = y;
+  *state_out = state;
+  return (GdkWindow *)w;
+}
+
 static void
 switch_to_pointer_grab (GdkDisplay *display,
                        GdkPointerGrabInfo *grab,
@@ -910,8 +946,7 @@ switch_to_pointer_grab (GdkDisplay *display,
                        guint32 time,
                        gulong serial)
 {
-  GdkWindow *src_window, *pointer_window;
-  GdkWindowObject *w;
+  GdkWindow *src_window, *pointer_window, *new_toplevel;
   GList *old_grabs;
   GdkModifierType state;
   int x, y;
@@ -944,66 +979,66 @@ switch_to_pointer_grab (GdkDisplay *display,
                                          src_window, grab->window,
                                          GDK_CROSSING_GRAB, time, serial);
            }
-         
+
          /* !owner_event Grabbing a window that we're not inside, current status is
             now NULL (i.e. outside grabbed window) */
          if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window)
            _gdk_display_set_window_under_pointer (display, NULL);
        }
-  
+
       grab->activated = TRUE;
     }
-  else if (last_grab)
+
+  if (last_grab)
     {
-      pointer_window = _gdk_windowing_window_at_pointer (display,  &x, &y, &state);
-      if (pointer_window != NULL &&
-         (GDK_WINDOW_DESTROYED (pointer_window) ||
-          GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
-          GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
-       pointer_window = NULL;
-      
-      /* We force checked what window we're in, so we need to
-       * update the toplevel_under_pointer info, as that won't get told of
-       * this change.
-       */
-      if (display->pointer_info.toplevel_under_pointer)
-       g_object_unref (display->pointer_info.toplevel_under_pointer);
-      display->pointer_info.toplevel_under_pointer = NULL;
-      
-      if (pointer_window)
+      new_toplevel = NULL;
+
+      if (grab == NULL /* ungrab */ ||
+         (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
+       {
+         /* We force check what window we're in, and update the toplevel_under_pointer info,
+          * as that won't get told of this change with toplevel enter events.
+          */
+         if (display->pointer_info.toplevel_under_pointer)
+           g_object_unref (display->pointer_info.toplevel_under_pointer);
+         display->pointer_info.toplevel_under_pointer = NULL;
+
+         new_toplevel = get_current_toplevel (display, &x, &y, &state);
+         if (new_toplevel)
+           {
+             /* w is now toplevel and x,y in toplevel coords */
+             display->pointer_info.toplevel_under_pointer = g_object_ref (new_toplevel);
+             display->pointer_info.toplevel_x = x;
+             display->pointer_info.toplevel_y = y;
+             display->pointer_info.state = state;
+           }
+       }
+
+      if (grab == NULL) /* Ungrabbed, send events */
        {
-         /* Convert to toplevel */
-         w = (GdkWindowObject *)pointer_window;
-         while (/*w->parent != NULL && */
-                w->parent->window_type != GDK_WINDOW_ROOT)
+         pointer_window = NULL;
+         if (new_toplevel)
            {
-             x += w->x;
-             y += w->y;
-             w = w->parent;
+             /* Find (possibly virtual) child window */
+             pointer_window =
+               _gdk_window_find_descendant_at (new_toplevel,
+                                               x, y,
+                                               NULL, NULL);
            }
          
-         /* w is now toplevel and x,y in toplevel coords */
-         display->pointer_info.toplevel_under_pointer = g_object_ref (w);
+         if (pointer_window != last_grab->window)
+           synthesize_crossing_events (display,
+                                       last_grab->window, pointer_window,
+                                       GDK_CROSSING_UNGRAB, time, serial);
          
-         /* Find (possibly virtual) child window */
-         pointer_window =
-           _gdk_window_find_descendant_at ((GdkWindow *)w,
-                                           x, y,
-                                           NULL, NULL);
-       }
+         /* We're now ungrabbed, update the window_under_pointer */
+         _gdk_display_set_window_under_pointer (display, pointer_window);
 
-      if (pointer_window != last_grab->window)
-       synthesize_crossing_events (display,
-                                   last_grab->window, pointer_window,
-                                   GDK_CROSSING_UNGRAB, time, serial);
-      
-      /* We're now ungrabbed, update the window_under_pointer */
-      _gdk_display_set_window_under_pointer (display, pointer_window);
-      
-      if (last_grab->implicit_ungrab)
-       generate_grab_broken_event (last_grab->window,
-                                   FALSE, TRUE, 
-                                   NULL);
+         if (last_grab->implicit_ungrab)
+           generate_grab_broken_event (last_grab->window,
+                                       FALSE, TRUE,
+                                       NULL);
+       }
     }
   
   display->pointer_grabs = old_grabs;